package GameObj;
import Component.GameComponent;
import Component.GraphComponent;
import Component.ComponentPackage;
import Scene.Layer;

import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONArray;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

import java.util.*;

import Scene.Renderable;

import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import Clock.*;
import Component.GameComponent;
public class GameObject implements Renderable, IUpdate
{
	boolean bVis_ = true;
	protected Rectangle boundingbox = new Rectangle();
	protected Rectangle absBB = new Rectangle();
	String InstName;
	String templateName;
	public GameComponent[] components;
	public ArrayList<Renderable> renderables = new ArrayList<Renderable>();
	
	Vector2 vPos = new Vector2(0,0); 
	Vector2 vScale = new Vector2(1,1);
	float fRot = 0;
	
	protected boolean bCanProcessMouse = false;
	
	public boolean GetCanProcMouse()
	{
		return bCanProcessMouse;
	}
	
	public void SetCanProcMouse(boolean bProc)
	{
		bCanProcessMouse = bProc;
	}
	
	public void SetPos(Vector2 v)
	{
		vPos = v;
	}
	
	public void SetPos(float x, float y)
	{
		vPos.x = x;
		vPos.y = y;
	}
	
	public Vector2 GetPos()
	{
		return vPos;
	}
	
	public void SetScale(Vector2 v)
	{
		vScale = v;
	}
	
	public void SetScale(float x, float y)
	{
		vScale.x = x;
		vScale.y = y;
	}
	
	public Vector2 GetScale()
	{
		return vScale;
	}
	
	public float GetRot()
	{
		return fRot;
	}
	
	public void SetRot(float rot)
	{
		fRot = rot;		
	}
	
	public void SetVisible(boolean bVis)
	{
		bVis_ = bVis;
	}
	
	public void Load(String fileName)
	{
		FileHandle hFile = Gdx.files.internal(fileName);
		String data = hFile.readString();
		
		try
		{
			JSONObject json = new JSONObject(data);
			LoadInternal(json);
		}
		catch(JSONException e)
		{
		
		}		
	}	
	
	public void LoadInternal(JSONObject json)
	{
		try
		{
		// loading component
			if (json.has("procMouse"))
			{
				bCanProcessMouse = json.getInt("procMouse") == 1;				
			}
			
					JSONArray comps = json.getJSONArray("comps");
					
					components = new GameComponent[comps.length()];
					for(int i = 0; i < comps.length(); ++i)
					{
						JSONObject jsonComp = comps.getJSONObject(i);		
						int nType = jsonComp.getInt("type");
						GameComponent comp = GameComponent.createComponetByType(nType, this);
						if (comp != null)
						{
							comp.Load(jsonComp);
							components[i] = comp;	
							
							if (comp.getClass().equals(GraphComponent.class) )
							{
								Renderable renderable = (Renderable)comp;
								if (renderable != null)
								{
									renderables.add(renderable);						
								}				
							}
							else if (comp.getClass().equals(ComponentPackage.class))
							{
								ComponentPackage comppack = (ComponentPackage)comp;
								ArrayList<GameComponent> retval = new ArrayList<GameComponent>();
								comppack.RecursiveGetComponents(retval);
								
								for (int j = 0; j < retval.size(); ++j)
								{
									GameComponent subcomp = retval.get(j);
									if (subcomp.getClass().equals(GraphComponent.class) )
									{
										Renderable renderable = (Renderable)subcomp;
										if (renderable != null)
										{
											renderables.add(renderable);						
										}				
									}
								}
							}
								
						}
					}	
		}
		catch(JSONException e)
		{
		
		}
		
		RecaculateBB();
	}
	
	public void Load(JSONObject json)
	{
		try
		{		
			InstName = json.getString("name");
			int x = json.getInt("x");
			int y = json.getInt("y");
			SetPos(x, y);
			
			float dx = 1;
			float dy = 1;
			if (json.has("sx"))
			{
				dx = (float)json.getDouble("sx");				
			}
			if (json.has("sy"))
			{
				dy = (float)json.getDouble("sy");				
			}
			
			SetScale(dx, dy);
			

			
			if (json.has("file"))
			{
				String filename = json.getString("file");	
				Load(filename);
				return;
			}
			
			LoadInternal(json);

		}
		catch(JSONException e)
		{
		
		}

	}
	
	public void Render(SpriteBatch spriteBatch, Matrix4 matrix)
	{
		Matrix4 matrixOut = matrix.cpy();
		
		matrixOut.scale(vScale.x, vScale.y, 1);
		matrixOut.rotate(0, 0, 1, fRot * 180);
		
		Matrix4 matrixTrans = new Matrix4();
		matrixTrans.translate(vPos.x, vPos.y, 0);
		matrixTrans.mul(matrixOut);
				
		for (int i = 0; i < renderables.size(); ++i)
		{
			Renderable renderable = renderables.get(i);
			renderable.Render(spriteBatch, matrixTrans);			
		}		
	}	

	public void Update(Clock clock)
	{
		for(int i = 0; i < components.length; ++i)
		{
			components[i].Update(clock);			
		}
	}
	
	public String GetInstName()
	{
		return InstName;
	}
	
	public String GetTemplateName()
	{
		return templateName;
	}
	
	// recaculate bounding box
	public void RecaculateBB()
	{
		boolean bInnerFlag = true;
		for (int i = 0; i < components.length && bInnerFlag; ++i)
		{
			GameComponent comp = components[i];
			if (comp.GetTypeId() == GameComponent.E_GRAPHCOMPONENT)
			{
				GraphComponent gp = (GraphComponent)comp;
				boundingbox = gp.GetBoundingBox();	
				break;
			}
			
			else if (comp.GetTypeId() == GameComponent.E_PACKAGECOMPONENT)
			{
				ComponentPackage packcomp = (ComponentPackage)comp;
				ArrayList<GameComponent> retval = new ArrayList<GameComponent>();
				packcomp.QueryComponentsByType(GameComponent.E_GRAPHCOMPONENT, retval);
				
				for (int j = 0; j < retval.size(); ++j)
				{
					GameComponent compInner = retval.get(j);
					if (compInner.GetTypeId() == GameComponent.E_GRAPHCOMPONENT)
					{
						GraphComponent gp = (GraphComponent)compInner;
						boundingbox = gp.GetBoundingBox();	
						bInnerFlag = false;
						break;
					}
				}
			}
				
				
			
		}
	}
	
	// recaculate bounding box
	public Rectangle GetAbsBB()
	{
		absBB.x = boundingbox.x * vScale.x + vPos.x;
		absBB.y = boundingbox.y * vScale.y + vPos.y;
		absBB.width = boundingbox.width *  vScale.x;
		absBB.height = boundingbox.height * vScale.y;
		return absBB;
	}
	
	public Rectangle GetBoundingBox()
	{
		return boundingbox;
	}
	
	public void SetBoundingBox(Rectangle rt)
	{
		boundingbox = rt;
	}
	
	// not including this
	public void QueryComponentsByType(int type, ArrayList<GameComponent> retval, boolean bEnabled)
	{
		if (retval == null)
		{
			retval = new ArrayList<GameComponent>();
		}
		if (components != null)
		{

			for(int i = 0; i < components.length; ++i)
			{
				GameComponent comp = components[i];
				if (comp.GetTypeId() ==  type )
				{
					if (comp.GetEnable() == bEnabled)
					{
						retval.add(comp);
					}
				}
				else if (comp.GetTypeId() ==  GameComponent.E_PACKAGECOMPONENT)
				{
					ComponentPackage comppack = (ComponentPackage)comp;
					comppack.QueryComponentsByType(type, retval, bEnabled);					
				}
						
			}
		}
		
	}
	
	public void QueryComponentsByType(int type, ArrayList<GameComponent> retval)
	{
		if (retval == null)
		{
			retval = new ArrayList<GameComponent>();
		}
		if (components != null)
		{

			for(int i = 0; i < components.length; ++i)
			{
				GameComponent comp = components[i];
				if (comp.GetTypeId() ==  type)
				{
					retval.add(comp);
				}
				else if (comp.GetTypeId() ==  GameComponent.E_PACKAGECOMPONENT)
				{
					ComponentPackage comppack = (ComponentPackage)comp;
					comppack.QueryComponentsByType(type, retval);					
				}
						
			}
		}
	}
	
}
